import { ClearOutlined, DeleteOutlined, FullscreenOutlined, ReloadOutlined } from '@ant-design/icons';
import { useMount, useRequest, useSafeState } from 'ahooks';
import { Button, Card, CardProps, Col, Divider, Drawer, Empty, Flex, Input, Row, Skeleton, Space, Spin, Typography } from 'antd';
import axios from 'axios';
import { concat, filter, find, findIndex, head, includes, isEmpty, isEqual, isFunction, keys, map, omit, uniq, without } from 'lodash';
import { memo, useMemo, useRef } from 'react';
import Markdown from 'react-markdown';
import { v4 } from 'uuid';
import { getAnswer } from './common/api';
import { deepseek_free_style } from './style';

type RequseType = { q: string; k?: string };

type ItemType = CardProps & { key: string, title: string };

type StorageType = { question: string; choices: any };

const { Title } = Typography;

const CancelToken = axios.CancelToken;

const storageKey = 'deepseek_free_answer';
const getStorage = () => JSON.parse(localStorage.getItem(storageKey) || '{}');
const setStorage = (storage: StorageType) => localStorage.setItem(storageKey, JSON.stringify(storage));

const clearStorage = () => localStorage.clear();

const DeepSeekFree = () => {
  const [answer, setAnswer] = useSafeState<ItemType[]>([]);
  const [question, setQuestion] = useSafeState<string>();
  const [reloadloading, setReloadLoading] = useSafeState(false);
  const [reloadKey, setReloadKey] = useSafeState<string[]>([]);
  const [open, setOpen] = useSafeState(false);
  const [selectedKey, setSelectedKey] = useSafeState<string>();

  const source = useRef(CancelToken.source());

  const selectedContent = useMemo(() => find(answer, ['key', selectedKey]), [selectedKey, answer]);

  // 获取回答
  const { run, loading } = useRequest(
    ({ q }: RequseType) => getAnswer(
      q,
      {
        cancelToken: source.current.token
      }
    ),
    {
      debounceWait: 300,
      manual: true,
      onSuccess(res: any, req) {
        if (!isEmpty(res?.choices)) {
          answerHandler(res.choices, head(req));
        }
      },
      onBefore(req) {
        const key = head(req)?.k;
        const reloadIndex = findIndex(answer, i => isEqual(i.key, key));

        if (reloadIndex >= 0) {
          setReloadLoading(true);
          setReloadKey(k => uniq(filter(concat(k, key))) as string[]);
        }
      },
      onFinally(req) {
        setReloadLoading(false);
        setQuestion(undefined);
        setReloadKey(k => without(k, head(req)?.k) as string[]);
      }
    }
  );

  // 回答处理
  const answerHandler = (choices: any[], req?: RequseType) => {
    const answerIndex = findIndex(answer, i => isEqual(i.key, req?.k));
    const storage = getStorage();

    if (answerIndex >= 0) {
      answer[answerIndex] = {
        ...answer[answerIndex],
        children: genChild(choices)
      };
      setAnswer(answer);

      if (req?.k) {
        storage[req.k] = { question: answer[answerIndex].title, choices };
        setStorage(storage);
      }
    } else if (question) {
      const key = v4();
      const answerTemp = concat(
        answer,
        {
          key: key,
          title: question,
          children: genChild(choices)
        }
      );
      setAnswer(answerTemp);
      storage[key] = { question, choices };
      setStorage(storage);
    }
  };

  // 内容显示
  const genChild = (choices: any[]) => map(
    choices,
    i => (<Markdown key={v4()}>{ i.message.content }</Markdown>)
  );

  // 按钮组 - 删除、重新生成
  const genExtra = (q: string, k: string, ghost?: boolean) => (
    <Space size={ghost ? 0 : 5}>
      <Button
        className='answer-extra'
        ghost={ghost}
        disabled={loading}
        icon={(<DeleteOutlined />)}
        onClick={e => (e.stopPropagation(), deleteHandler(k))}
      />
      <Button
        className='answer-extra'
        ghost={ghost}
        disabled={loading}
        icon={(<ReloadOutlined />)}
        onClick={e => (e.stopPropagation(), run({q, k}))}
      />
      {
        ghost && (
          <Button
            className='answer-extra'
            ghost
            icon={(<FullscreenOutlined />)}
            onClick={e => (e.stopPropagation(), openHandler(k))}
          ></Button>
        )
      }
    </Space>
  );

  // 取消生成
  const cancelHandler = () => {
    source.current.cancel();
  };

  // 删除
  const deleteHandler = (k: string) => {
    setOpen(false);
    const index = findIndex(answer, i => isEqual(i.key, k));

    if (index >= 0) {
      const storage = getStorage();

      setStorage(omit(storage, [k]) as StorageType);
      setAnswer(ans => filter(ans, i => !isEqual(i.key, k)));
    }
  };

  // 清空
  const clearHandler = () => {
    setAnswer([]);
    clearStorage();
  };

  // 生成
  const commitHandler = () => {
    if (question) {
      source.current = CancelToken.source();
      run({q: question});
    }
  };

  // 打开详情
  const openHandler = (k: string) => {
    setSelectedKey(k);
    setOpen(true);
  };

  // 初始化
  const init = () => {
    const node = head(document.getElementsByClassName('ant-tabs'));
    const storage = getStorage();

    if (isFunction(node?.remove)) {
      node.remove();
    }

    setAnswer(map(
      keys(storage),
      k => ({
        key: k,
        title: storage[k].question,
        children: genChild(storage[k].choices)
      })
    ))
  };

  useMount(() => { init(); });

  return (
    <>
      <Flex
        className={deepseek_free_style}
        vertical
        justify='space-between'
        gap={isEmpty(answer) ? 40 : 5}
      >
        { !isEmpty(answer) && (
            <Flex justify='end'>
              <Button
                danger
                type='text'
                size='small'
                autoInsertSpace
                onClick={clearHandler}
                icon={(<ClearOutlined />)}
              >清空</Button>
            </Flex>
          )
        }
        <Row
          className='answer-container'
          gutter={[10, 10]}
          align='top'
          justify='start'
        >
          {
            map(
              answer,
              i => (
                <Col
                  key={i.key}
                  xs={24}
                  sm={12}
                  md={12}
                  lg={8}
                  xl={8}
                  xxl={6}
                >
                  <Card
                    className='answer-card'
                    size='small'
                    hoverable
                    title={i.title}
                    children={i.children}
                    loading={includes(reloadKey, i.key)}
                    extra={genExtra(i.title, i.key, true)}
                    onClick={() => openHandler(i.key)}
                  />
                </Col>
              )
            )
          }
          {
            isEmpty(answer) &&
            (
              <Flex
                className='answer-empty'
                align='center'
                justify='center'
              >
                <Spin spinning={loading}><Empty /></Spin>
              </Flex>
            )
          }
          {
            loading && !reloadloading && !isEmpty(answer) && (<Skeleton active />)
          }
        </Row>
        {
          loading && (
            <Button
              type='primary'
              autoInsertSpace
              onClick={cancelHandler}
            >取消</Button>
          )
        }
        {
          !loading && (
            <Space.Compact>
              <Input
                allowClear
                placeholder='请输入。。。'
                value={question}
                disabled={loading}
                onPressEnter={commitHandler}
                maxLength={50}
                showCount
                onChange={e => setQuestion(e.target.value)}
              />
              <Button
                type='primary'
                autoInsertSpace
                loading={loading}
                disabled={isEmpty(question)}
                onClick={commitHandler}
              >发送</Button>
            </Space.Compact>
          )
        }
      </Flex>
      <Drawer
        closable
        destroyOnClose
        width='100vw'
        placement='right'
        open={open}
        loading={loading && includes(reloadKey, selectedContent?.key)}
        title='详情'
        onClose={() => setOpen(false)}
        extra={
          selectedContent?.title &&
          selectedContent?.key &&
          genExtra(selectedContent?.title, selectedContent?.key)
        }
      >
        <Title level={4}>{ selectedContent?.title }</Title>
        <Divider />
        { selectedContent?.children }
      </Drawer>
    </>
  );
};

export default memo(DeepSeekFree);